<!--
@description    漏斗分析
@author         秦俊强
@email          458112865@qq.com
@create         2021-05-26
-->

<template>
  <div class="funnelAnalysis" v-loading="loading">
    <!-- 侧边弹窗 编辑/添加 漏斗 start -->
    <el-drawer
      :title="getDrawerTitle()"
      :visible.sync="showEditFunnel"
      :modal-append-to-body="false"
      :size="800"
      append-to-body
    >
      <EditFunnel
        ref="editFunnelRel"
        :d="editFunnelVal"
        @close="showEditFunnel = false"
        @showeditbool="editFlag"
        @getFunnelsEvent="getFunnels"
      ></EditFunnel>
    </el-drawer>
    <!-- 侧边弹窗 编辑/添加 漏斗 end -->

    <!-- 模块标题区 start -->
    <div class="headerBox">
      <div class="title">漏斗分析</div>
      <preserVation
        :bookmarkId="analysisOpts.value.bookmarkId"
        @format="formatData"
        :obj="obj"
      ></preserVation>
    </div>
    <!-- 模块标题区 end -->

    <!-- 筛选项区 start -->
    <div class="filterBox">
      <!-- 显示漏斗 start -->
      <div class="viewFunnelBox">
        <span class="title-size">显示漏斗</span>

        <el-select
          size="mini"
          filterable
          :title="analysisOpts.value.name"
          value-key="id"
          v-model="analysisOpts.value"
          @change="analysisChange"
        >
          <el-option
            v-for="item in analysisOpts.options"
            :style="{ 'max-width': '600px' }"
            :key="item.id"
            :value="item"
            :label="item.name"
            :title="item.name"
          ></el-option>
        </el-select>

        <!-- 编辑漏斗 -->
        <el-button
          type="warning"
          size="mini"
          icon="el-icon-edit"
          plain
          @click="editFunnel('edit')"
          >编辑当前漏斗</el-button
        >

        <!-- 创建漏斗 -->
        <el-button
          type="primary"
          size="mini"
          icon="el-icon-plus"
          plain
          @click="editFunnel('add')"
          >创建新漏斗</el-button
        >
      </div>
      <!-- 显示漏斗 end -->

      <!-- 按 xx 查看漏斗 start -->
      <div class="viewFunnelBox">
        <span class="title-size">按</span>

        <el-select
          size="mini"
          @change="funnelChange()"
          placeholder="总体"
          multiple
          filterable
          clearable
          value-key="name"
          v-model="viewFunnelTypes.arr_check"
          :style="{ width: '443px' }"
        >
          <el-option
            v-for="item in viewFunnelTypes.commonOpts"
            :key="item.name"
            :value="item"
            :style="{ 'max-width': '600px' }"
            :label="item.cname"
            :title="item.cname"
          ></el-option>
        </el-select>

        <span style="color: #808080;">查看</span>
      </div>
      <!-- 按 xx 查看漏斗 end -->

      <!-- 设置筛选条件 start -->
      <CustomScreen ref="customScreenRef"></CustomScreen>
      <!-- 设置筛选条件 end -->

      <!-- 设置筛选条件 -->
      <div class="settingCondition">
        <el-button
          type="primary"
          icon="el-icon-search"
          size="small"
          style="width: 192px"
          @click="searchFunnel()"
          >分析计算</el-button
        >

        <el-button
          type="text"
          icon="el-icon-plus"
          size="small"
          @click="editCond()"
          >全局筛选条件</el-button
        >
      </div>
    </div>
    <!-- 筛选项区 end -->

    <!-- 主内容区 start -->
    <div class="contentBox">
      <div class="titleBox">
        <i class="el-icon-data-line"></i>
        <span>「{{ analysisOpts.value.name }}」漏斗</span>
      </div>

      <div class="childFilterBox">
        <!-- 切换视图 趋势 | 对比 -->
        <el-radio-group v-model="state" size="mini" @change="stateChange()">
          <el-radio-button :label="'trends'">趋势</el-radio-button>
          <el-radio-button :label="'overview'">对比</el-radio-button>
        </el-radio-group>

        <div class="contrastFunnelBox">
          <span
            v-if="viewFunnelTypes.arr_check.length <= 0 && state === 'overview'"
            >* 需选择按分组查看以获取对比选项</span
          >

          <div
            class="selectedBox"
            v-if="
              state === 'overview' &&
                viewFunnelTypes.arr_check.length > 0 &&
                contrastFunnel.opts.length > 0
            "
          >
            <el-select
              size="mini"
              value-key="ind"
              @change="contrastChange"
              v-model="contrastFunnel.selecteds[0]"
            >
              <el-option
                v-for="item in contrastFunnel.opts"
                :key="item.ind"
                :value="item"
                :label="item.name"
                :title="item.name"
              ></el-option>
            </el-select>

            <span class="vs">VS</span>

            <el-select
              size="mini"
              value-key="ind"
              @change="contrastChange"
              v-model="contrastFunnel.selecteds[1]"
            >
              <el-option
                v-for="item in contrastFunnel.opts"
                :key="item.ind"
                :value="item"
                :label="item.name"
                :title="item.name"
              ></el-option>
            </el-select>
          </div>
        </div>

        <!-- 窗口期 -->
        <div class="winPeriodBox">
          <el-date-picker
            format="yyyy-MM-dd"
            value-format="yyyy-MM-dd"
            type="daterange"
            size="mini"
            range-separator="至"
            :picker-options="pickerOptions"
            v-model="winPeriod"
            :clearable="false"
            style="width: 220px;"
          ></el-date-picker>

          <div class="title">
            <p>窗口期</p>
            <p>7天</p>
          </div>
        </div>
      </div>

      <!-- 趋势 视图 start -->
      <el-row
        :gutter="40"
        v-if="state === 'trends' && funnelReportResData.funnelDetail"
      >
        <!-- 对比-左 -->
        <el-col :span="12">
          <ViewFunnel :funnelReportResData="funnelReportResData"></ViewFunnel>
        </el-col>

        <!-- 对比-右 图表 -->
        <el-col :span="12">
          <el-container>
            <div id="chart"></div>
          </el-container>
        </el-col>
      </el-row>
      <!-- 趋势 视图 end -->

      <!-- 对比 视图 start -->
      <el-row
        :gutter="40"
        v-if="state === 'overview' && funnelReportResData.funnelDetail"
      >
        <!-- 对比-左 -->
        <el-col :span="12">
          <ViewFunnel
            :funnelReportResData="funnelReportResData"
            :byValues="contrastFunnel.selecteds[0]"
          ></ViewFunnel>
        </el-col>

        <!-- 对比-右 -->
        <el-col :span="12">
          <ViewFunnel
            :funnelReportResData="funnelReportResData"
            :byValues="contrastFunnel.selecteds[1]"
          ></ViewFunnel>
        </el-col>
      </el-row>
      <!-- 对比 视图 end -->

      <!-- 表格 -->
      <TableFunnel :funnelReportResData="funnelReportResData"></TableFunnel>
    </div>
    <!-- 主内容区 end -->
  </div>
</template>

<script>
/* 添加/编辑漏斗弹窗组件 */
import EditFunnel from "./editFunnel";

/*  表格展示组件 */
import TableFunnel from "./tableFunnel";

/* 漏斗视图组件 */
import ViewFunnel from "./viewFunnel";

/* 自定义筛选条件 */
import CustomScreen from "./customScreen";

/*漏斗分析保存*/
import preserVation from "./preserVation";

/**
 * api 接口
 * */
import {
  getFunnelList,
  propertyList,
  funnelReportRes
} from "./api.config.js";

export default {
  name: "funnelAnalysis",
  components: {
    EditFunnel,
    TableFunnel,
    ViewFunnel,
    CustomScreen,
    preserVation
  },
  data() {
    return {
      obj:{},
      loading: true,

      showEditFunnel: false, // 添加/编辑 漏斗弹窗
      editFunnelVal: null,

      /* 显示漏斗选项 */
      analysisOpts: {
        options: [],
        value: {}
      },

      /* 按xx查看漏斗 & 设置筛选条件 */
      viewFunnelTypes: {
        commonOpts: [],

        arr_check: [], // 按xx查看
        arr_setting: [] // 设置筛选条件
      },

      /* 视图类型 */
      state: "trends", // trends 趋势 | overview 对比

      /* 且 and | 或 or */
      relation: { key: "and", name: "且" },

      /* 趋势图表 */
      chartView: {},

      /* 接口原始数据 */
      funnelReportResData: {},

      /* 窗口期 */
      winPeriod: ["", ""],

      /* 日期选择器，不能选择今天以后的日期 */
      pickerOptions: {
        disabledDate(time) {
          return time.getTime() > Date.now() - 8.64e6;
        }
      },

      /* 对比漏斗 */
      contrastFunnel: {
        opts: [], // 可选对比项
        selecteds: ["", ""] // 已选
      }
    };
  },

  created() {
    /**
     * TODO 初始化窗口期，数字 7 应该为动态，暂时写死 7 天，即当前时间往前 7 天的窗口期日期范围
     * 7 - 1 说明含今天，实际就会只有 7 天
     * 只传 7 ，说明不含今天，其实会显示 8 天
     * */
    this.winPeriod[0] = this.getBeforeDate(7 - 1);
    this.winPeriod[1] = this.getBeforeDate();

    this.getFunnels();
  },

  mounted() {
    this.$nextTick(() => {
      // 监听 window 窗口变化，自适应图表
      window.addEventListener("resize", this.autoChart);
    });
  },

  methods: {
    // 编辑组件传过来的布尔值
    editFlag(bool) {
      console.log("触发");
      console.log(bool);
      this.showEditFunnel = bool;
    },

    /* edit 编辑 | add 添加 漏斗 */
    editFunnel(str) {
      if (str === "edit") { this.editFunnelVal = this.analysisOpts.value; }
      if (str === "add") { this.editFunnelVal = null; }

      // 拦截提示，如果是编辑漏斗，但是没有选择漏斗
      if (str === "edit" && (!this.editFunnelVal || !this.editFunnelVal.id)) {
        this.$alert('当前无可编辑漏斗，请先创建漏斗', '提示', { type: 'warning' });
        return;
      }

      // 显示右侧弹窗
      this.showEditFunnel = true;

      setTimeout(() => {
        // 清空 editFunnelRel 数据
        this.$refs.editFunnelRel.initializeData();

        // 给 editFunnelRel 控件发送当前选择数据
        if (str === "edit") {
          this.$refs.editFunnelRel.receiveDate(this.editFunnelVal);
        }
      }, 500);
    },

    /* 返回 编辑/添加 漏斗弹窗 title */
    getDrawerTitle() {
      if (!this.editFunnelVal) {
        return "创建漏斗";
      }
      return "编辑漏斗";
    },

    /* 监听【显示漏斗】下拉菜单值的改变 */
    analysisChange() {
      console.log("显示漏斗 = ", this.analysisOpts.value);
    },

    /* 监听【按xx查看】下拉选项值的改变 */
    funnelChange() {
      console.log("按 xx 查看 = ", this.viewFunnelTypes.arr_check);
    },

    /* 视图类型切换 */
    stateChange() {
      if (this.state === "trends") {
        this.viewChart();
      }
    },

    /* 监听对比下拉选项改变 */
    contrastChange() {
      console.log("监听对比下拉选项改变");
    },

    /* 渲染图表 */
    viewChart() {
      let t = this;

      // 如果当前是 对比 视图，则不需要展示图表
      if (t.state === "overview") {
        return;
      }

      let dom = document.getElementById("chart");
      t.chartView = t.$echarts.init(dom);

      // 图表模板
      let tem = {
        xAxis: {
          type: "category",
          axisLabel: { interval: 0, rotate: -40 },
          data: []
        },
        tooltip: {
          trigger: "axis"
        },
        legend: {
          data: []
        },
        yAxis: {
          type: "value",
          axisLabel: {
            formatter: "{value} %"
          }
        },
        series: []
      };

      let funnelReportResData = t.funnelReportResData;
      let dateList = funnelReportResData.dateList;
      let funnelDetail = funnelReportResData.funnelDetail;
      let eventNames = funnelReportResData.eventNames;

      // 图表横坐标，因为 dateList 第 0 个是 '$ALL'，所以从第 1 个开始
      for (let i = 1; i < dateList.length; i++) {
        tem.xAxis.data.push(dateList[i]);
      }

      // 步骤
      for (let i = 0; i < eventNames.length; i++) {
        let size = i === 0 ? "总体转化" : "第 " + i + " 步转化";
        tem.legend.data.push(size);
        tem.series.push({
          name: size,
          type: "line",
          data: [],

          // 参考线/辅助线
          markLine: { data: [{ type: "average", name: "平均值" }] }
        });
      }

      // 坐标值
      for (let i = 1; i < dateList.length; i++) {
        let item = funnelDetail[i];

        for (let j = 0; j < item.steps.length; j++) {
          let cItem = item.steps[j];
          if (j === 0) {
            tem.series[j].data.push(item.completionRate);
          } else {
            tem.series[j].data.push(cItem.conversionRate);
          }
        }
      }

      t.chartView.clear();
      t.chartView.setOption(tem);
      t.autoChart();
    },

    /* 图表大小自适应 */
    autoChart() {
      // 如果当前是 对比 视图，则不需要渲染图表
      if (this.state === "overview") {
        return;
      }

      this.chartView && this.chartView.resize();
    },

    /* 添加 add 筛选条件 */
    editCond() {
      this.$refs.customScreenRef.editCond();
    },

    /* 返回 byFields */
    getByFields() {
      let arr = [];
      let arrCheck = this.viewFunnelTypes.arr_check;

      if (arrCheck.length === 0) {
        return arr;
      }

      for (let i = 0; i < arrCheck.length; i++) {
        let item = arrCheck[i];
        arr.push(item.name);
      }

      return arr;
    },

    /* 初始化对比选项 */
    initContrastFunnelOpts() {
      let t = this;
      t.contrastFunnel.opts = [];
      t.contrastFunnel.selecteds = [
        { ind: 0, name: "总体" },
        { ind: 0, name: "总体" }
      ];

      if (t.viewFunnelTypes.arr_check.length <= 0) {
        return;
      }

      let byValuesList = t.funnelReportResData.byValuesList;
      for (let i = 0; i < byValuesList.length; i++) {
        let arr = byValuesList[i];
        let str = "";

        for (let j = 0; j < arr.length; j++) {
          let val = arr[j];
          str = str + val + (j === arr.length - 1 ? "" : ", ");
        }

        if (i === 0) {
          t.contrastFunnel.opts.push({ ind: 0, name: "总体" });
        } else {
          t.contrastFunnel.opts.push({ ind: i, name: str });
        }
      }

      // 默认总体
      t.contrastFunnel.selecteds[0] = t.contrastFunnel.opts[0];
      t.contrastFunnel.selecteds[1] = t.contrastFunnel.opts[1];
    },

    formatData() {
      console.log(this.funnelReportResData);
      var arr = [];
      this.$refs.customScreenRef.arrSetting.map(item => {
        var unit = {
          field: item.dbColumnName,
          function: item.new_data_type.key,
          params: item.customArr
        };
        arr.push(unit);
      });

      var obj = {
        fromDate: this.winPeriod[0],
        toDate: this.winPeriod[1],
        funnelId: this.analysisOpts.value.id,
        by_field_steps: [0, 1],
        bookmarkid: "57789",
        byFields: this.viewFunnelTypes.arr_check,
        bucketParams: {},
        filter: {
          conditions: arr
        },
        filter_field_steps: [0],
        sub_task_type: "FUNNEL"
      };
      console.log(obj);
      this.obj=obj;

      console.log(this.$refs.customScreenRef.arrSetting);
      console.log(77);
    },

    /* 查询漏斗内容 */
    searchFunnel() {
      let t = this;
      t.loading = true;
      let appid = this.$store.state.global.appItem.appId;

      // 没有选择漏斗，或没有漏斗选项时，不往下执行
      if (!t.analysisOpts.value.id) {
        t.loading = false;

        this.$message('请选择显示漏斗', '提示', { type: 'warning' });
        return;
      }

      let param = {
        id: t.analysisOpts.value.id,

        funnelId: t.analysisOpts.value.id, // 当前已选漏斗 id
        byFields: t.getByFields(), // 按 xx 查看

        filter: this.$refs.customScreenRef.getFilterConditions(), // 自定义漏斗筛选

        fromDate: t.winPeriod[0], // 窗口期 开始时间
        toDate: t.winPeriod[1], // 窗口期 结束时间

        sub_task_type: "FUNNEL", // 漏斗模块写死的值

        // TODO 以下字段前期默认空值
        byFieldSteps: [],
        filterFieldSteps: [],
        bucketParams: {},
        bookmarkid: ""
      };

      funnelReportRes(param, appid)
        .then(res => {
          console.log("漏斗内容 = ", res.data);

          // TODO 特殊接口，暂不需要弹窗提示
          /*if (res.code !== 200) {
            t.loading = false;
            this.$alert(res.data.msg, '提示', { type: 'warning'});
            return;
          }*/

          // 接口返回成功后 loading 150 毫秒后消失，因为太快消失的话用户看不见 loading，一闪而过了
          setTimeout(() => {
            t.loading = false;
          }, 150);

          t.funnelReportResData = res.data;
          t.initContrastFunnelOpts();
          this.formatData();

          setTimeout(() => {
            t.viewChart();
          });
        })
        .catch(error => {
          t.loading = false;
          console.log("error = ", error);
        });
    },

    /* 获取【漏斗】下拉菜单列表 */
    getFunnels() {
      let t = this;
      t.loading = true;

      let param = { limit: 1000 };
      getFunnelList(param)
        .then(res => {

          console.log(res.data.code, res.data.msg);
          // 返回状态码如果不是 200，说明数据异常，需弹窗提示
          if (res.data.code !== 200) {
            t.loading = false;
            this.$alert(res.data.msg, '提示', { type: 'warning'});
            return;
          }

          let data = res.data.data;

          if (data && data.rows && data.rows[0]) {
            t.analysisOpts.options = data.rows;
            t.analysisOpts.value = t.analysisOpts.options[0];
          } else {
            t.analysisOpts.options = [];
            t.analysisOpts.value = {};
          }

          this.getFunnelCondition();
        })
        .catch(error => {
          t.loading = false;
          console.log("error = ", error);
        });
    },

    /* 获取【按 xx 条件查看】下拉菜单选项 */
    getFunnelCondition() {
      let t = this;
      t.loading = true;

      let param = {
        events: '_Anything',
        type: "event",
        needEventTime: true
      };

      propertyList(param)
        .then(res => {
          // 返回状态码如果不是 200，说明数据异常，需弹窗提示
          if (res.data.code !== 200) {
            t.loading = false;
            this.$alert(res.data.msg, '提示', { type: 'warning'});
            return;
          }

          t.viewFunnelTypes.commonOpts = res.data.data.rows;
          this.searchFunnel();
        })
        .catch(error => {
          t.loading = false;
          console.log("error = ", error);
        });
    },

    /**
     * 返回前 number 天的日期，参数 number 为前几天
     *
     * 不传 number，返回当前时间 yyyy-MM-dd
     * 传 number，例如 7，返回当前时间往前 7 天的时间
     * */
    getBeforeDate(number) {
      let num = number;
      let date = new Date();

      let year = date.getFullYear();
      let mon = date.getMonth() + 1;
      let day = date.getDate();

      if (typeof num === "number") {
        if (day <= num) {
          if (mon > 1) {
            mon = mon - 1;
          } else {
            year = year - 1;
            mon = 12;
          }
        }

        date.setDate(date.getDate() - num);

        year = date.getFullYear();
        mon = date.getMonth() + 1;
        day = date.getDate();
      }

      return (
        year +
        "-" +
        (mon < 10 ? "0" + mon : mon) +
        "-" +
        (day < 10 ? "0" + day : day)
      );
    }
  }
};
</script>

<style scoped lang="scss">
.funnelAnalysis {
  padding: 15px;
}

.headerBox .title {
  font-size: 18px;
  font-weight: bold;
  padding-left: 10px;
}

.filterBox,
.contentBox {
  padding: 10px 15px;
  background-color: #ffffff;
  border-radius: 5px;
  margin: 15px 0;
}

/* 筛选项区 */
.filterBox {
  .viewFunnelBox {
    padding: 10px 0;
    border-bottom: 1px solid #e7e7e7;
    position: relative;

    button {
      height: 27px;
    }

    .title-size {
      display: inline-block;
      width: 80px;
      padding: 0 10px;
      text-align: right;
    }

    .el-select {
      margin-right: 10px;
    }
  }

  .funnelSettingBox {
    border-left: 2px solid #6fd3b3;
    padding: 5px 0 5px 97px;
    position: relative;

    &:hover {
      background-color: #fafafa;
    }

    /deep/input[type="number"] {
      padding-right: 0;
    }

    .el-select {
      margin-right: 10px;
    }

    .size {
      padding-right: 5px;
    }

    .betweenBox,
    .datetimeBox {
      display: inline-block;
    }
  }

  i.el-icon-delete {
    position: absolute;
    right: 20px;
    top: 50%;
    transform: translate(0, -50%);
    cursor: pointer;

    &:hover {
      color: rgb(247, 86, 94);
    }
  }

  .andOrNotBox,
  .lineBox {
    position: absolute;
    top: 50%;
  }
  /* 且或非 */
  .andOrNotBox {
    width: 26px;
    height: 26px;
    font-size: 12px;
    text-align: center;
    line-height: 26px;
    border: 1px solid #cccccc;
    background-color: #fafafa;
    border-radius: 3px;
    cursor: pointer;
    z-index: 10;
    transform: translate(46px, -50%);
  }

  .lineBox {
    width: 26px;
    border: 1px solid #cccccc;
    border-right: none;
    transform: translate(60px, -50%);
    z-index: 5;
  }

  /* 设置筛选条件 */
  .settingCondition {
    padding: 10px 10px 0 100px;
  }
}

/* 主内容区 */
.contentBox {
  .titleBox {
    text-align: center;
    font-size: 16px;
    font-weight: bold;
    padding: 10px 0;
    margin-bottom: 10px;
  }

  .childFilterBox {
    padding: 10px 0 15px 0;
    margin-bottom: 20px;
    border-bottom: 1px solid #e7e7e7;
    overflow: hidden;

    .winPeriodBox {
      float: right;

      .title {
        float: right;
        font-size: 12px;

        p {
          margin: -2px 0 -2px 10px;
        }
        p:nth-child(1) {
          color: #cccccc;
        }
      }
    }

    .el-radio-group {
      float: left;
    }
    .el-range-editor.el-input__inner {
      padding: 0 10px;
    }

    /deep/.el-range-editor--mini .el-range__close-icon {
      display: none;
    }
    /deep/.el-range-editor--mini .el-range-separator {
      line-height: 25px;
    }

    /* 对比选项 */
    .contrastFunnelBox {
      font-size: 12px;
      display: inline-block;
      padding: 0 10px;

      .vs {
        padding: 0 5px;
        font-size: 14px;
        font-weight: bold;
      }
    }
  }

  .el-row {
    margin-right: 0 !important;
    margin-left: 0 !important;
    margin-bottom: 50px;

    .el-col:nth-child(1) {
      height: 420px;
      border-right: 1px solid #e7e7e7;
      padding-left: 0 !important;
      overflow: auto;
    }

    .el-col:nth-child(2) {
      padding-right: 0 !important;
    }
  }

  /*.el-row .el-col,*/
  #chart {
    width: 100%;
    height: 400px;
    position: relative;
  }
}
</style>
